home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
UTILITY
/
CMDED2E6.ARJ
/
EDIT.ASM
< prev
next >
Wrap
Assembly Source File
|
1992-06-30
|
30KB
|
1,163 lines
; EDIT.ASM
; (c) 1989, 1990 Ashok P. Nadkarni
;
; This module contains the line editing functions of CMDEDIT.
; Macro disable toggle added by dfa, December 1990.
; Ability to switch ESC to filename completion added by dfa, May 1991.
; Twiddle key and filename display added by wd.
; Disable backslash appending to directory name added by dfa, June 1992.
; Tab completion cycling added by wd and dfa, June 1992.
PUBLIC get_kbd_line
PUBLIC auto_recall
PUBLIC expand_fnkey
PUBLIC BKS_key_function ;Added by wd
PUBLIC ESC_key_function ;Added by dfa
PUBLIC TAB_key_function ;Added by dfa
PUBLIC backslash_char ;Added by dfa & wd
PUBLIC getkey_funcnum ;Added by wd
INCLUDE common.inc
INCLUDE buffers.inc ;Added by wd
INCLUDE ascii.inc
INCLUDE BIOS.INC
INCLUDE DOS.INC
INCLUDE GENERAL.INC
CSEG SEGMENT PARA PUBLIC 'CODE'
CSEG ENDS
DGROUP GROUP CSEG
ASSUME CS:DGROUP, DS:DGROUP, SS:DGROUP, ES:DGROUP
CSEG SEGMENT PARA PUBLIC 'CODE'
EXTRN linebuf:BYTE
EXTRN lastchar:WORD
EXTRN caller_cursor:WORD
EXTRN dot:WORD
EXTRN edit_mode:BYTE
EXTRN omode_cursor:WORD
EXTRN disable_macro:BYTE ;added by dfa
EXTRN initial_currow:BYTE ;added by wd
EXTRN sym_stk:WORD
EXTRN LINEBUF_END:ABS
; These 7 lines added by wd
FFBLK_SAVE_SIZE equ 30
ffblk_save db FFBLK_SAVE_SIZE dup (?)
CycleFlags db 0 ;bit 0 == 1 if cmd is cycle_complete
;bit 1 == 1 if last cmd was ''
fnameptr dw 0 ;fname location in linebuf
olddot dw 0 ;Remember where dot was
tempchar db ? ;Temporary storage
auto_recall db 0 ;By default no auto recall
auto_recall_on db ? ;1 if auto-recall in effect,
; else 0
continue_recall db ? ;auto-recall state variable
backslash_char db '\' ;added by dfa & wd
fnkey_tab db 'S','F',0 ;Used to look for function key
; definitions.
fnkey_exec_char db '@' ;If the last character a fn key
; definition is this, the key is
; executed immediately
getkey_funcnum db 8 ;what function to use for getkey
; Must be IDENTICAL to the string in CMDCONF.C including the
; terminating '\0' byte. This must be followed immediately by ctrl_key_defs.
cmdedit_keymap_id db 'CMDEDIT key map',0
; ctrl_key_redefs is used to allow the cmdconf program to remap the control
; keys. Each entry corresponds to a control key. It must immediately follow
; cmdedit_keymap_id.
ctrl_key_redefs LABEL WORD
x = 0
REPT 32 ;32 control keys
DW x
x = x + 1
ENDM
EXTRN disp_line:PROC
EXTRN hist_back:PROC
EXTRN hist_fwd:PROC
EXTRN hist_bck_match:PROC
EXTRN hist_fwd_match:PROC
EXTRN remember:PROC
EXTRN execute_auto_recall:PROC
EXTRN insert_at_dot:PROC
EXTRN erase_to_dot:PROC
EXTRN isalphnum:PROC
EXTRN set_disp_marks:PROC
EXTRN bell:PROC
EXTRN line_to_scr:PROC
EXTRN isspace:PROC
EXTRN xlate_lower:PROC
EXTRN expand_var:PROC
EXTRN ismacsym:PROC
EXTRN get_symbol:PROC
EXTRN tolower:PROC ;added by wd
EXTRN disp_prompt:PROC ;added by wd
EXTRN get_curpos:PROC ;added by wd
EXTRN output_newline:PROC ;added by wd
;number of command keys
NUM_CMD_KEYS EQU (cmd_key_jumps-cmd_key_table)/2
;+
; FUNCTION : get_kbd_line
;
; Gets a line from the user and stores it in linebuf. The length
; of the line is stored in global linelen. The name is a misnomer
; because the line is from standard input, not necessarily from
; the keyboard.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
get_kbd_line proc near
@save si,di
mov al,auto_recall
mov auto_recall_on,al ;Indicate if auto-recall is enabled
mov continue_recall,1 ;Init auto-recall memory
; Main editing loop
@get_kbd_line_10:
mov al,continue_recall
and auto_recall_on,al ;Indicate if we should keep
; auto-recalling
mov continue_recall,0 ;Reset the flag. It will be set
; for the default actions keys.
call near ptr disp_line ;Show current line
shl CycleFlags,1 ;shift the cycle_complete flag (wd)
mov ah,getkey_funcnum ;might be a raw keystroke (wd)
call near ptr getkey ;get next key from the user
and CycleFlags,6 ;assume this cmd isn't a cycle_complete
; mov si,ax ;si holds the character (not used--wd)
cmp ax,32 ;Control character ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,ax ;DI used to calculate
add di,di ; offset into table
mov ax,ctrl_key_redefs[di] ;Mapping of key
; mov si,ax ;(not used -- wd)
cmp ax,32 ;Control char ?
jge @get_kbd_line_15 ;No, then check if fn key
mov di,ax ;DI used to calculate
add di,di ; offset into table
jmp ctrl_key_table[di] ;Branch according to control char
@get_kbd_line_15: ;Check if function key
cmp ax,256+59 ;>= F1 ?
jb @get_kbd_line_20 ;No, then check next table
cmp ax,256+68 ;<= F10
jg @get_kbd_line_20 ;Not fn key
jmp @fn_key ;Handle the function key
@get_kbd_line_20:
cmp ax,256+84 ;>= Shift-F1 ?
jb @get_kbd_line_25 ;No, then check next table
cmp ax,256+93 ;<= Shift-F10
jg @get_kbd_line_25 ;
jmp @sfn_key ;Handle the shifted function key
@get_kbd_line_25:
mov cx,NUM_CMD_KEYS ;size and...
mov bx,offset DGROUP:cmd_key_table ;beginning of jump table
@get_kbd_line_30: ;Loop begin
cmp ax,cs:[bx] ;Is this the key ?
je @get_kbd_line_40 ;Hurrah, found
inc bx ;point to next key
inc bx
loop @get_kbd_line_30 ;If more keys, repeat
jmp short @default_action ;key not in table
@get_kbd_line_40: ;Jump to location associated with
jmp word ptr cs:[bx+(2*NUM_CMD_KEYS)] ;key
@quote: ;Insert next char
; without interpreting it
mov ah,7 ;get a raw keystroke (wd)
call near ptr getkey
@default_action: ;Insert the character (in AX)
call near ptr store_char
jc @get_kbd_line_10 ;No room for char, keep looping
mov al,auto_recall_on ;Are we auto-recalling ?
or al,al
jz @get_kbd_line_10 ;No
call near ptr execute_auto_recall
jc @get_kbd_line_10 ;If carry set, no matching
; string in history buffer
mov continue_recall,1 ;Else indicate auto-recall is
; still to go on
jmp @get_kbd_line_10
@char_left: ;Cursor one char left
call near ptr char_left ;char_left will return to top
jmp @get_kbd_line_10
; of editing loop
@char_right: ;Cursor one char right
call near ptr char_right ;char_right will return to top
jmp @get_kbd_line_10
; of editing loop
@word_left: ;Cursor one word left
call near ptr word_left
jmp @get_kbd_line_10
@word_right: ;Cursor one word right
call near ptr word_right
jmp @get_kbd_line_10
@bol: ;Beginning of line
call near ptr go_bol
jmp @get_kbd_line_10
@eol: ;End of line
call near ptr go_eol
jmp @get_kbd_line_10
@prev_line: ;Get previous history line
mov ax,offset DGROUP:hist_back
@history_line:
call ax
mov ax,lastchar
mov dot,ax ;Leave cursor at end of line
@history_search:
jnc @history_line_done ;Line found
call near ptr strstk_settop ;added by wd
call near ptr bell ;No line
@history_line_done:
jmp @get_kbd_line_10
@next_line: ;Get next history line
mov ax,offset DGROUP:hist_fwd
jmp short @history_line
@search_back: ;Search back thru history buffer
mov ax,offset DGROUP:hist_bck_match
@search:
mov di,dot ;Save current dot
call ax
mov dot,di ;Restore it
jmp short @history_search
@search_forw: ;Search forward thru history buffer
mov ax,offset DGROUP:hist_fwd_match
jmp short @search
@cycle_complete:
or CycleFlags,1
@complete: ;Try to find a matching filename
call near ptr match_file
cmp auto_recall_on,1 ;Autorecall ongoing?
je short @del_eol ;Yes, then delete to end of line
jmp @get_kbd_line_10
@del_left: ;Delete char before cursor
mov ax,offset dgroup:char_left
jmp short @delete
@del_right: ;Delete char at cursor
mov ax,offset dgroup:char_right
jmp short @delete
@del_prev_word: ;Delete upto word beginning
mov ax,offset dgroup:word_left
jmp short @delete
@del_next_word: ;Delete to start of next word
mov ax,offset dgroup:word_right
jmp short @delete
@del_bol: ;Delete to beginning of line
mov ax,offset dgroup:go_bol
jmp short @delete
@toggle_insert:
mov ax,1
xor al,edit_mode ;Toggle edit mode
mov edit_mode,al
xchg ax,bx
add bx,bx ;Word offset
mov cx,omode_cursor[bx] ;cx<-cursor shape
mov ah,01h ;Set cursor size function
IF TOGGLE_CURSOR
int 10h ;BIOS
ENDIF
jmp @get_kbd_line_10 ;Repeat editing loop
@abort_and_store: ;Erases current line but remembers
; it in the history buffer
call near ptr remember
; Fall through to erase line
@erase_line:
call near ptr go_bol ;Move dot to beginning of line
; fall thru to delete to end of line
@del_eol: ;Delete to end of line
mov ax,offset dgroup:go_eol
@delete: ;General purpose delete
mov si,dot ;Remember the dot
call ax ;Move dot to new position
xchg si,ax
call near ptr erase_to_dot ;Delete characters between ax and dot
jmp @get_kbd_line_10
@twiddle: ;added by wd
mov si,dot
cmp si,lastchar
jne @twiddle_10
call near ptr char_left
jc @ignore
dec si
@twiddle_10:
call near ptr char_left
jc @ignore
xor ah,ah
push ax
xchg si,ax
call near ptr erase_to_dot
call near ptr char_right
pop ax
jmp @default_action
@cooked_char: ;added by wd
mov ah,8 ;get a cooked keystroke (wd)
call near ptr getkey
jmp @default_action
@autorecall:
xor auto_recall,1 ;Toggle auto recall mode
jmp @get_kbd_line_10
@macro: ;added by dfa
xor disable_macro,1 ;Toggle macro,symbol expansion disable
jmp @get_kbd_line_10
@vars:
; Expand the variables on the line.
call near ptr expand_var
jmp @get_kbd_line_10 ;Ignore return status from expand_var
@ignore:
jmp @get_kbd_line_10 ;Ignore the character
ctrl_key_table LABEL WORD
dw @ignore ;NUL or ^@
dw @bol ;^A
dw @char_left ;^B
dw @cooked_char ;^C (changed by wd - was @ignore)
dw @del_right ;^D
dw @eol ;^E
dw @char_right ;^F
dw @abort_and_store ;^G
dw @del_left ;^H
TAB_key_function label word ; (label added by dfa)
dw @complete ;^I
dw @vars ;^J might have to be @ignore in order for input
; redirection to work properly but try for
; var expansion anyway.
dw @del_eol ;^K
dw @del_prev_word ;^L
dw @done_editing ;^M
dw @next_line ;^N
dw @del_eol_exec ;^O
dw @prev_line ;^P (changed by wd - was @ignore)
dw @quote ;^Q
dw @search_back ;^R
dw @ignore ;^S
dw @twiddle ;^T (changed by wd - was @ignore)
dw @prev_line ;^U
dw @search_forw ;^V
dw @del_next_word ;^W
dw @del_bol ;^X
dw @autorecall ;^Y
dw @default_action ;^Z
ESC_key_function label word ; (label added by dfa)
dw @erase_line ;^[ or ESC
BKS_key_function label word ; (label added by wd)
dw @cycle_complete ;^\
dw @ignore ;^]
dw @done_wipeout ;^^
dw @macro ;^_ (changed by dfa - was @ignore)
cmd_key_table: ;table of command keys
dw 127 ;DEL
dw 327 ;HOME
dw 328 ;UP
dw 331 ;LEFT
dw 333 ;RIGHT
dw 335 ;END
dw 336 ;DOWN
dw 338 ;INS
dw 339 ;KDEL
dw 371 ;CTLLEFT
dw 372 ;CTLRIGHT
cmd_key_jumps:
dw @del_left ;DEL
dw @bol ;HOME
dw @prev_line ;UP
dw @char_left ;LEFT
dw @char_right ;RIGHT
dw @eol ;END
dw @next_line ;DOWN
dw @toggle_insert ;INS
dw @del_right ;KDEL
dw @word_left ;CTLLEFT
dw @word_right ;CTLRIGHT
@sfn_key:
; A shifted function key has been struck.
; (Treat same as an unshifted function key).
@fn_key:
; A function key has been struck.
call near ptr expand_fnkey
jc @fn_key_20 ;Error or no expansion
or dx,dx ;Line to be executed
; immediately ?
je short @done_editing_2 ;Yes, all done
@fn_key_20:
jmp @get_kbd_line_10 ;else keep editing
@del_eol_exec: ;Deletes characters from the dot
; to end of the line and then
; executes the line
mov si,dot ;Remember the dot
call go_eol
xchg si,ax
call near ptr erase_to_dot
jmp short @done_editing
@done_wipeout:
; The line is executed. However it is not stored in the history buffer and
; is also removed from the screen (this is a little klugy).
mov ax,offset DGROUP:linebuf
mov dot,ax
mov dx,lastchar
mov lastchar,ax ;Temporarily pretend line
; is empty
xchg ax,dx
push ax
call near ptr set_disp_marks
call disp_line
pop ax
mov lastchar,ax ;Restore line length
jmp short @get_kbd_line_90
@done_editing:
call near ptr remember ;Store in history buffer
; Picks up line from global linebuf
@done_editing_2:
call near ptr disp_line ;Necessry for @del_eol_exec,
; might as well do for others
mov ax,lastchar
mov dot,ax ;Set dot to end of line
call near ptr line_to_scr ;Set cursor beyond last character
@get_kbd_line_90:
@DispCh CR ;Do a carraige return because
; some applications like EDLIN
; only do a LF to go to next line
; @DispCh LF ;Go onto next line
; all done
@get_kbd_line_99:
@restore
ret
get_kbd_line endp
;+
; FUNCTION : getkey
;
; Read a keystroke, interpreting function keys into a 16-bit value.
;
; Parameters:
; AH = 7 for a raw keystroke, 8 for a cooked keystroke
;
; Returns:
; AX = 16-bit key value
; Register(s) destroyed:
; DL
;-
; Requires AH be set to either 7 (raw) or 8 (cooked)
;
getkey proc near
mov dl,ah
int 21h
mov ah,0
or al,al
jne @114 ;not '\0'
mov ah,0Bh
int 21h ;check if key available
or al,al
jz @113 ;no character available
mov ah,dl
int 21h
mov ah,1
jmp short @114
@113:
xor ax,ax
@114:
ret
getkey endp
;+
; FUNCTION : expand_fnkey
;
; Inserts the expansion corresponding to a symbol key into the
; linebuffer. If the buffer is too small, only as many characters as
; possible are inserted and the function returns an error. The
; function also returns an error if the symbols is not defined. The
; function also updates the displayed line. The function also checks
; if the line is to be executed immediately or not, based on the last
; character of the fn key expansion.
;
; Parameters:
; AX = function key character, must be between (256+59)-(256+68)
; function keys and (256+84)-(256+93) for shifted functin keys.
;
; Returns:
; CF = 0 if no error, else 1
; If CF is 1, then AX is 0 if symbol not found or non-zero
; if symbol found but no room in line.
; AX = 1 if symbol was present
; 0 if symbol was not found.
; DX = 0 if the line is to be executed immediately
; non-0 otherwise
; DX is only valid if CF=0 and AX=1
; Register(s) destroyed:
; <TBA>
;-
expand_fnkey proc near
@save si,di
push bp
mov bp,sp
sub sp,LINEBUF_SIZE
exp_buf equ <byte ptr [bp-LINEBUF_SIZE]>
mov si,offset DGROUP:fnkey_tab ;SI->'SFn'
mov dx,3 ;DX<-length of string
mov di,si
sub ax,256+59
cmp ax,10 ;Is it a function key
jnb @expand_fnkey_10 ;No, shifted function key
inc si ;SI->'Fn'
dec dx ;length of string is 2
jmp short @expand_fnkey_15
@expand_fnkey_10:
sub ax,84-59
@expand_fnkey_15:
cmp ax,9 ;F10 must appear as F0
jne @expand_fnkey_20
mov al,'0'-'1'
@expand_fnkey_20:
add al,'1'
mov 2[di],al ;Store in 'SFn' string
; OK now try and expand the symbol.
; SI->symbol
mov ax,LINEBUF_SIZE
xchg ax,dx ;AX<-length of synbol
; DX<-length of expansion buffer
lea di,exp_buf
call near ptr get_symbol ;Params SI,AX,DI,DX
jc @expand_fnkey_99 ;No symbol (buffer too
; small case not possible).
; AX will be 0 for this case.
; OK now we have the symbol expansion, so try insert it into the linebuffer.
; AX contains length of expansion
mov si,di ;SI->expansion
add di,ax
dec di ;DI->last char of expansion
xor dx,dx
mov dl,byte ptr [di]
sub dl,fnkey_exec_char ;Is this line to be
; immediately executed
jne @expand_fnkey_80 ;No
dec ax ;The last char of expansion
; is a special char. Do not
; include it in the insert
; string
@expand_fnkey_80:
push dx
call near ptr insert_at_dot ;Params SI,AX
; pushf ;Save CF
; call disp_line
; popf ;Restore CF
mov ax,1 ;AX<-exit code
pop dx ;DX is 0 if line is to be
; executed immediately
@expand_fnkey_99:
mov sp,bp
pop bp
@restore
ret
expand_fnkey endp
;+
; FUNCTION : store_char
;
; Stores the character in AX into the line buffer if max line
; length will not be exceeded. Characters may be inserted or
; overwrite chars in the buffer depending on the edit mode and whether
; auto-recall is on.
;
; Parameters:
; AX = character
;
; Returns:
; CF = 0 if no error, else 1
; Register(s) destroyed:
; <TBA>
;-
store_char proc near
@save si
cmp ax,256 ;char >= 256
jnb @store_char_90 ;Ignore if so
cmp edit_mode,0 ;1 if insert mode
je @store_char_20 ;Jump if overtype mode
cmp auto_recall_on,1 ;Is auto-recall on ?
je @store_char_20 ;Yes, behave as if in overtype mode
mov si,offset dgroup:tempchar ;temporary storage
mov [si],al ;Store char
mov ax,1 ;Length of string
call near ptr insert_at_dot ;Insert the character
jnc @store_char_99 ;No problemo
jmp short @store_char_90 ;No room in buffer
@store_char_20:
mov si,dot ;Current position in line
cmp si,LINEBUF_END ;At line end?
jae @store_char_90
; Enough room for a char
mov [si],al ;Store the char
mov dx,si ;DX->changed character
mov ax,si
inc ax ;AX->char after change
mov dot,ax ;Store it as new dot position
cmp si,lastchar ;Was it end of line ?
jb @store_char_30
mov lastchar,ax ;Store new end of line
@store_char_30:
call near ptr set_disp_marks ;ax,dx parameters
clc ;Indicate no error
jmp short @store_char_99
@store_char_90:
call near ptr bell
stc ;Indicate error
@store_char_99:
@restore
ret
store_char endp
;+
; FUNCTION : word_left
;
; Move one word left.
;
; Parameters:
; Globals linebuf and dot.
;
; Returns:
; CF = 1 if dot was at beginning of the line already
; 0 otherwise.
; Register(s) destroyed:
;-
word_left proc near
@word_left_10:
call near ptr char_left ;Move one char left
jc @word_left_99 ;Already at beginning of line
@word_left_12:
;Loop to backup over non-alphanum
call near ptr isalphnum ;AL alphanumeric?
jnc @word_left_15 ;Yes
call near ptr char_left ;One char left.
;AL<-char at dot
jnc @word_left_12 ;Not at beginning of line
@word_left_15: ;Now backup to beginning of word
; At this point, dot is always at a alphabetic char or beginning
; of the line
call near ptr char_left
jc @word_left_98 ;Were already at beginning of line
call near ptr isalphnum ;Alphanumeric?
jnc @word_left_15 ;Yes, loop back
;Found non-alphanumeric char
call near ptr char_right ;move over one
@word_left_98:
clc ;Clear carry flag
@word_left_99:
ret
word_left endp
;+
; FUNCTION : word_right
;
; Move one word right.
;
; Parameters:
; Globals linebuf and dot.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
word_right proc near
@word_right_10: ;Loop fwd over alphanumerics
call near ptr char_right ;One char right
;AL<-char at dot
jc @word_right_99 ;Already at end of line
call near ptr isalphnum ;Is AL alphanumeric ?
jnc @word_right_10 ;Yes, loop back
@word_right_15: ;Now move to beginning of word
call near ptr char_right
jc @word_right_99 ;Already at end of line
call near ptr isalphnum ;Alphanumeric?
jc @word_right_15 ;Not alphanum char, loop back
@word_right_99:
ret
word_right endp
;+
; FUNCTION : char_left
;
; Moves the 'dot' one character to the left unless
; already at the beginning of the line.
;
; Parameters:
; Global dot is current position in the line.
;
; Returns:
; AL = char at new dot position.
; CF = 1 if OLD dot was at beginning of line
; 0 otherwise.
; Register(s) destroyed:
;-
char_left proc near
@save si
mov ax,dot ;Current position in line
cmp ax,offset dgroup:linebuf
jne @char_left_5
stc ;Dot already at beginning of line
jmp short @char_left_99
@char_left_5:
dec ax ;Move dot left
mov dot,ax
@char_left_99:
xchg ax,si
lodsb ;AL<-char at dot
@restore
ret
char_left endp
;+
; FUNCTION : char_right
;
; Moves the 'dot' one character to the right unless
; already at the end of the line.
;
; Parameters:
; Global dot is current position in the line.
;
; Returns:
; AL = char at new dot position. Undefined if new dot is at
; the end of the line.
; CF = 1 if OLD dot was already at end of the line.
; 0 otherwise.
; Register(s) destroyed:
;-
char_right proc near
@save si
mov si,dot ;Current position in line
mov ax,lastchar ;AX->Beyond last char
dec ax ;AX->last char in line
cmp ax,si ;Dot at end ?
jc @char_right_99 ;Already at line end
inc si ;Move dot right, CF not affected
mov dot,si
lodsb ;AL<-char at dot, (undefined if
; dot is now at end of line).
; CF already clear
@char_right_99:
@restore
ret
char_right endp
;+
; FUNCTION : go_bol
;
; Sets dot to pint to the beginning of the line
;
; Register(s) destroyed: None.
;-
go_bol proc near
mov dot,offset dgroup:linebuf
ret
go_bol endp
;+
; FUNCTION : go_eol
;
; Sets dot to pint to the end of the line
;
; Register(s) destroyed: AX.
;-
go_eol proc near
mov ax,lastchar
mov dot,ax
ret
go_eol endp
;+
; FUNCTION : match_file
;
; match_file tries to expand the filename to the left of the
; cursor. If there are several matching files, the longest common
; prefix is placed on the line.
; Added by wd: If no characters can be placed on the line,
; list the possible matches. Alternately, add
; one match at a time to the line.
;
; Parameters:
; None.
;
; Returns:
; Nothing.
; Register(s) destroyed:
;-
match_file proc near
@save si,di
push bp
mov bp,sp
sub sp,64+44+2+2+2+2+2
pathbuf equ 64 ;Storage for entire filename with path
ffblk equ pathbuf+44
ffblk_attr equ ffblk-15h ;Attr byte within ffblk
ffblk_name equ ffblk-1Eh ;filename within ffblk
lineptr equ ffblk+2
remaining equ lineptr+2 ;Remembers remaining space in path
oldDTAseg equ remaining+2
oldDTAoff equ oldDTAseg+2
breakstate equ oldDTAoff+2 ;Remembers break state
mov ax,3300h ;Get current break state
int 21h ;DL<-current break state
mov byte ptr [bp-breakstate],dl ;Remember it
xor dl,dl
mov ax,3301h ;Disable break check during
; disk i/O
int 21h
push es
@GetDTA ;Get and save old DTA
mov [bp-oldDTAseg],es
mov [bp-oldDTAoff],bx
pop es
;
lea dx,[bp-ffblk]
@SetDTA dx ;Set DTA to our DTA
; If the last call was also a cycle, continue what we started (wd,dfa)
cmp CycleFlags,7
je @match_file_60
; lea di,[bp-pathbuf] ;OK 'cause SS==DS (removed by wd)
mov si,dot ;Current line position
mov olddot,si ;Remember current dot position (wd)
mov cx,63 ;Max length of path
@match_file_10:
cmp si,offset dgroup:linebuf
je @match_file_51 ;Beginning of line and filename
dec si
mov al,[si] ;AL<-next char
@match_file_25:
call near ptr isspace
je @match_file_50 ;Beginning of filename
@match_file_45: ;Check for next char if
; pathname not too long
loop @match_file_10
jmp @match_file_90 ;Pathname too long, just exit
@match_file_50:
inc si
@match_file_51:
mov [bp-lineptr],si ;Save start of path name in linebuf
mov ax,63
sub ax,cx ;Length of name
mov [bp-remaining],cx ;remember num bytes left in pathbuf
xchg ax,cx ;CX<-length of name
; jcxz @match_file_90 ;No name, just exit (removed by wd)
call near ptr @match_file_parse
lea dx,[bp-pathbuf] ;dx->ASCII name
@GetFirst dx,16 ;Include subdirs in search
jnc @match_file_70 ;No error
@match_file_58:
mov ffblk_save,0 ;Make sure the DTA will fail a GetNext
call near ptr bell ;No files found
jmp @match_file_90 ;Restore DTA and exit
@match_file_60:
mov cx,FFBLK_SAVE_SIZE/2 ;5 lines by dfa and wd
mov si,offset ffblk_save
lea di,[bp-ffblk]
rep movsw ;restore the DTA for the GetNext
and CycleFlags,3 ;Don't need more than this now
@match_file_65:
@GetNext ;Get the next file name
jnc @match_file_70 ;Got one
mov ax,olddot ;AX->start of chars to be deleted
call near ptr erase_to_dot ;Delete characters between dot
mov CycleFlags,1 ;If next key is cycle, want to do
jmp short @match_file_58 ;it immediately
@match_file_70: ;At least one file found
lea di,[bp-pathbuf] ;DI->pathbuf
lea si,[bp-ffblk_name] ;Name returned by GetFirst
cmp byte ptr [si],'.' ;Is this '.' or '..'?
je @match_file_65 ;Yes, ignore it
@match_file_71: ;Copy the file name
lodsb
stosb
or al,al
jne @match_file_71
mov ax,SPACE ;If file, add a space (ah = 0 -- wd)
test byte ptr [bp-ffblk_attr],16 ;Subdirectory?
je @match_file_72 ;No
mov al,backslash_char ;If subdir, (possibly) add a backslash
@match_file_72:
mov word ptr [di-1],ax ;Add a space or a '\' and a null
cmp CycleFlags,3 ;If cycling, bug out (wd,dfa)
je @match_file_79
; Now hunt for more files. For each file found, keep the longest
; prefix in common so far.
@GetNext ;Get the next file name
jc @match_file_80 ;No more files
lea di,[bp-pathbuf] ;DI->start of file name
lea si,[bp-ffblk_name] ;Name returned by GetNext
mov cx,13 ;Max Length of field
repe cmpsb ;Compare strings
xor ax,ax ;Terminating null for [di-1]
jmp short @match_file_72 ;Try for more files
@match_file_79:
mov cx,FFBLK_SAVE_SIZE/2 ;4 lines by dfa and wd
lea si,[bp-ffblk]
mov di,offset ffblk_save
rep movsw ;save ffblk for next call
@match_file_80:
; Found one or more files, copy the longest common prefix
; into the line buffer
;following 2 lines moved by wd
; mov ax,[bp-lineptr] ;AX->start of chars to be deleted
; call near ptr erase_to_dot ;Delete characters between dot
; and start of name
lea si,[bp-pathbuf] ;SI->name to be copied
mov di,si
xor al,al
mov cx,64
repne scasb ;Hunt for terminating null
mov ax,63
sub ax,cx ;AX<-length of string
;following 10 lines added by wd & dfa
cmp CycleFlags,3 ;If cycling, no length check
je @match_file_85
mov dx,dot
sub dx,fnameptr ;DX<-length of search string
cmp ax,dx
ja @match_file_85 ;If cycling, we want first call
jb @match_file_list ;not to actually cycle, but just
test CycleFlags,1 ;complete to longest common prefix
jz @match_file_list
jbe @match_file_list
@match_file_85:
test CycleFlags,1
jnz @match_file_87 ;If next key is cycle, want to do
mov CycleFlags,1 ;it immediately (dfa)
@match_file_87:
; SI->string, AX is length
push ax
call near ptr xlate_lower ;Convert to lowercase
;ok, these 2 lines removed above can now do their work - wd
mov ax,fnameptr ;AX->start of chars to be deleted
call near ptr erase_to_dot ;Delete chars between dot and start
pop ax
call near ptr insert_at_dot ;SI->source, AX == length
@match_file_90:
push ds
mov ds,[bp-oldDTAseg]
mov dx,[bp-oldDTAoff]
@SetDTA dx ;Restore DTA
pop ds
; Restore previous state of break checking
mov dl,byte ptr [bp-breakstate]
mov ax,3301h
int 21h
mov sp,bp
pop bp
@restore
ret
; remainder of this file extensively modified by wd
@match_file_list:
mov CycleFlags,1 ;If next key is cycle, want to do
;it immediately (dfa)
mov si,[bp-lineptr]
mov cx,dot
sub cx,si
call near ptr @match_file_parse
call near ptr output_newline
lea dx,[bp-pathbuf]
@GetFirst dx,16
@match_file_list_10:
lea si,[bp-ffblk_name]
cmp byte ptr [si],'.' ;Is this '.' or '..'?
je @match_file_list_55 ;Yes, ignore it
mov cx,15
@match_file_list_20:
lodsb
test al,al
jz @match_file_list_30
call near ptr tolower
@DispCh al
dec cx
jmp @match_file_list_20
@match_file_list_30:
mov al,SPACE
test byte ptr [bp-ffblk_attr],16 ;Subdirectory?
je @match_file_list_40 ;No
mov al,'\' ;If subdir, add a backslash
@match_file_list_40:
@DispCh al
@match_file_list_50:
@DispCh SPACE
loop @match_file_list_50
@match_file_list_55:
@GetNext
jnc @match_file_list_10
call near ptr get_curpos ;DX<-current cursor position
test dl,dl
jz @match_file_list_60
call near ptr output_newline
@match_file_list_60:
call near ptr disp_prompt
call near ptr get_curpos ;DX<-current cursor position
mov initial_currow,dh
mov ax,lastchar
mov dx,offset DGROUP:linebuf
call near ptr set_disp_marks
call disp_line ;Redisplay line
jmp @match_file_90
match_file endp
@match_file_parse proc near
; Copy filename into ASCIIZ buffer
; SI->first char of filename in line buffer, CX=length
xor dx,dx ;Flags
lea di,[bp-pathbuf] ;OK 'cause SS==DS
mov fnameptr,si ;Assumed start of filename in linebuf
jcxz @match_file_p42
@match_file_p0:
lodsb ;AL<-next char
stosb ;Store it
cmp al,'.'
jne @match_file_p10
or dl,1 ;Set flag to remember file type '.'
jmp short @match_file_p40 ;Check out next character
@match_file_p10:
cmp al,':' ;Disk?
je @match_file_p30
cmp al,'\' ;Directory separator?
je @match_file_p20
cmp al,'/' ;Same thing
jne @match_file_p40
@match_file_p20:
cmp backslash_char,0 ;is backslash appending turned on?
je @match_file_p30 ;no
mov backslash_char,al ;remember the type of slash (/ or \)
@match_file_p30:
mov fnameptr,si ;Update start of filename in linebuf
and dl,0FEh ;Forget file type flag
@match_file_p40:
loop @match_file_p0
@match_file_p42:
mov cx,[bp-remaining] ;CX<-remaining space
jcxz @match_file_p50 ;Only space for terminator
mov al,'*'
stosb ;Attach a '*'
cmp cl,3 ;Enough space for ".*"
jb @match_file_p50
and dl,1 ;Saw a file type ?
jne @match_file_p50 ;Yes, go attach terminator
mov [di],2A2Eh ;Attach a ".*"
inc di
inc di
@match_file_p50:
xor al,al ;AL<-0
stosb ;Terminating 0
ret
@match_file_parse endp
CSEG ENDS
END